package cn.shop.utils;

import java.util.*;
import java.util.Map.Entry;
import java.util.function.Consumer;
import java.util.function.Function;

import static cn.shop.utils.Utils.isNotEmpty;
import static java.util.Collections.singletonList;

/**
 * 构造Map内容的便利类，可以用Fluent的调用方式构造一个Map，模式为Putif.start() ... .get();
 * 
 * @author zhy
 *
 */
@SuppressWarnings("unused")
public final class Putif {
	
	private final Map<String, Object> map;
	
	private Putif(Map<String, Object> map) {
		this.map = map == null ? new HashMap<>() : map;
	}
	
	/** 
	 * 开始一个新Map。
	 */
	public static Putif start() {
		return new Putif(null);
	}
	
	/**
	 * 包装传入的Map，如果其为null，开始一个新Map。
	 */
	public static Putif start(Map<String, Object> map) {
		return new Putif(map);
	}
	
	/**
	 * 获取目前填好的Map。
	 */
	public Map<String, Object> get() {
		return map;
	}
	
	/**
	 * 将目前填好的Map放到一个单点集中返回。
	 */
	public List<Map<String, Object>> singleton() {
		return singletonList(map);
	}
	
	/**
	 * 获取目前填好的Map，如果其为空，返回null。
	 */
	public Map<String, Object> nullIfEmpty() {
		return map.isEmpty() ? null: map;
	}

	/**
	 * 将传入map的数据添加到本map中，已存在的key不变。
	 */
	public Putif append(Map<String, Object> map) {
		if (map != null && map != this.map && !map.isEmpty()) {
			for (Entry<String, Object> entry : map.entrySet()) {
				this.map.putIfAbsent(entry.getKey(), entry.getValue());
			}
		}
		return this;
	}
	
	/**
	 * 不论value是否为null，加到map的指定key下。
	 */
	public Putif anyway(String key, Object value) {
		map.put(key, value);
		return this;
	}
	
	/**
	 * 如果值不为null，将其加到map的指定key下。
	 */
	public Putif notNull(String key, Object value) {
		if (value != null) {
			map.put(key, value);
		}
		return this;
	}
	
	/**
	 * 如果字符串非null非空，加到map的指定key下。
	 */
	public Putif notEmpty(String key, String value) {
		if (isNotEmpty(value)) {
			map.put(key, value);
		}
		return this;
	}
	
	/**
	 * 如果集合非null非空，加到map的指定key下。
	 */
	public <T> Putif notEmpty(String key, Collection<T> value) {
		if (isNotEmpty(value)) {
			map.put(key, value);
		}
		return this;
	}
	
	/**
	 * 如果传入map非null非空，加到map的指定key下。
	 */
	public <K, V> Putif notEmpty(String key, Map<K, V> value) {
		if (isNotEmpty(value)) {
			map.put(key, value);
		}
		return this;
	}
	
	/**
	 * 如果value为正数，加到map的指定key下。
	 */
	public Putif positive(String key, Integer value) {
		if (value != null && value > 0) {
			map.put(key, value);
		}
		return this;
	}
	
	/**
	 * 如果value为正数，加到map的指定key下。
	 */
	public Putif positive(String key, int value) {
		if (value > 0) {
			map.put(key, value);
		}
		return this;
	}
	
	/**
	 * 如果value非负，加到map的指定key下。
	 */
	public Putif nonNegative(String key, Integer value) {
		if (value != null && value >= 0) {
			map.put(key, value);
		}
		return this;
	}
	
	/**
	 * 如果value非负，加到map的指定key下。
	 */
	public Putif nonNegative(String key, int value) {
		if (value >= 0) {
			map.put(key, value);
		}
		return this;
	}
	
	/**
	 * 如果value为正，加到map的指定key下。
	 */
	public Putif positive(String key, long value) {
		if (value > 0) {
			map.put(key, value);
		}
		return this;
	}
	
	/**
	 * 如果value为正，加到map的指定key下。
	 */
	public Putif positive(String key, double value) {
		if (value > 0) {
			map.put(key, value);
		}
		return this;
	}
	
	/**
	 * 如果value非零，加到map的指定key下。
	 */
	public Putif notZero(String key, double value) {
		if (value != 0) {
			map.put(key, value);
		}
		return this;
	}
	
	/**
	 * 如果value为true，加到map的指定key下。
	 */
	public Putif truth(String key, boolean value) {
		if (value) {
			map.put(key, true);
		}
		return this;
	}
	
	/**
	 * 如果coll非空，对其每个元素应用func进行变换，结果如果非null，放到一个列表中。
	 * 最终列表如果非空，加到map的指定key下。
	 */
	public <T, R> Putif each(String key, Collection<T> coll, Function<T, R> func) {
		if (coll == null || coll.isEmpty()) {
			return this;
		}
		List<R> list = new ArrayList<>();
		for (T obj : coll) {
			R result = func.apply(obj);
			if (result != null) {
				list.add(result);
			}
		}
		if (!list.isEmpty()) {
			map.put(key, list);
		}
		return this;
	}
	
	/**
	 * 如果传入map非空，对其每一项应用func进行变换，结果如果非null，放到一个列表中。
	 * 最终列表如果非空，加到map的指定key下。
	 */
	public <K, V, R> Putif each(String key, Map<K, V> map, Function<Entry<K, V>, R> func) {
		if (map == null || map.isEmpty()) {
			return this;
		}
		List<R> list = new ArrayList<>();
		for (Entry<K, V> entry : map.entrySet()) {
			R result = func.apply(entry);
			if (result != null) {
				list.add(result);
			}
		}
		if (!list.isEmpty()) {
			this.map.put(key, list);
		}
		return this;
	}
	
	/**
	 * 如果条件成立，调用consumer，把当前实例传给它，让它继续填写map。
	 */
	public Putif cond(boolean condition, Consumer<Putif> consumer) {
		if (condition) {
			consumer.accept(this);
		}
		return this;
	}

}
